# Convert Raw image data to JPEG
#
# Copyright (C) 2010 Yotam Medini <yotam.medini@gmail.com>
#
# This file is part of Gupicasa.
#
# Gupicasa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gupicasa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gupicasa.  If not, see <http://www.gnu.org/licenses/>.

import time # debug

import os
import os.path
import string
import gtk
import subprocess
import pyexiv2

# local
import convert
import debug
import ugtk
import usys


# Executable used
dcraw = "dcraw"
cjpeg = "cjpeg"


class Converter(gtk.Dialog):

    def __init__(self, parent, pattern="", icon=None):
        flags = gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT
        missing_dcraw = (usys.which(dcraw) is None)
        missing_cjpeg = (usys.which(cjpeg) is None)
        missing = missing_dcraw or missing_cjpeg
        buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
                 gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        if missing:
            buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        gtk.Dialog.__init__(self, title="Raw Images Converter",
                            parent=parent,
                            flags=flags,
                            buttons=buttons)
        self.source_files = []
        self.target_directory = None
        self.pattern = pattern
        self.icon = icon
        self.vbox.set_border_width(6)
        ugtk.pack_start_align(self.vbox,
                              gtk.Label("Convert raw images to JPEG format"),
                              align=ugtk.ALIGN_CENTER, padding=6)
        if missing:
            t = [dcraw if missing_dcraw else "", cjpeg if missing_cjpeg else ""]
            warn = gtk.Label()
            warn.set_markup("""
<b><span foreground="red">
 Missing tool(s) for conversion: %s
</span></b>"""[1:] % string.join(t))
            self.vbox.pack_start(warn, expand=True, fill=True, padding=4)
        stock = gtk.image_new_from_stock(gtk.STOCK_CONVERT,
                                         gtk.ICON_SIZE_BUTTON)
        hb = gtk.HBox()
        tbl = gtk.Table(2, 2)
        b_source = ugtk.StockButton(gtk.STOCK_OPEN)
        b_target = ugtk.StockButton(gtk.STOCK_DIRECTORY)
        b_source.connect('clicked', self.select_source_files)
        b_target.connect('clicked', self.select_target_directory)

        b_source.set_tooltip_text("""
Select raw images files
to convert from
a single directory"""[1:])
        b_target.set_tooltip_text("""
Select target directory for
the result JPEG files"""[1:])

        self.label_sources = ls = gtk.Label("None")
        self.label_target = lt = gtk.Label("None")
        ls.set_tooltip_text("Selected source raw format image files")
        lt.set_tooltip_text("Target directory for JPEG files")
        ugtk.attach1(tbl, b_source, 0, 0, xoptions=0, yoptions=gtk.EXPAND)
        ugtk.attach1(tbl, b_target, 0, 1, xoptions=0, yoptions=gtk.EXPAND)
        ugtk.attach1(tbl, ls, 1, 0, yoptions=0, pos=gtk.POS_LEFT, xpadding=2)
        ugtk.attach1(tbl, lt, 1, 1, yoptions=0, pos=gtk.POS_LEFT, xpadding=2)
        ugtk.pack_start_align(hb, stock, align=ugtk.ALIGN_CENTER, padding=2)
        ugtk.pack_start_align(hb, tbl, align=ugtk.ALIGN_CENTER,
                              expand=True, fill=True, padding=4)

        self.vbox.pack_start(hb)
        self.vbox.show_all()


    def run(self):
        debug.log("")
        response = gtk.Dialog.run(self)
        while response == gtk.RESPONSE_OK and (
            len(self.source_files) == 0 or self.target_directory is None):
            if len(self.source_files) == 0:
                ugtk.warning(self, """
Please select source raw images
for conversion.""")
            elif self.target_directory is None:
                ugtk.warning(self, """
Please select target directory
for JPEG files.""")
            response = gtk.Dialog.run(self)
        debug.log("response=%d, converting..." % response)
        if response == gtk.RESPONSE_OK:
            done = self.raw2jpeg()
            if not done:
                response = gtk.RESPONSE_CANCEL
        return response


    def select_source_files(self, w):
        debug.log("")
        dialog = gtk.FileChooserDialog("Open..", self,
                                       gtk.FILE_CHOOSER_ACTION_OPEN,
                                       (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
                                        gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        dialog.set_select_multiple(True)
        filter_all = gtk.FileFilter()
        filter_all.set_name("All files")
        filter_all.add_pattern("*")
        self.user_filter = None
        dialog.add_filter(filter_all)
        self.add_user_filter(dialog)
        ca = dialog.get_content_area()
        hbox = gtk.HBox()
        debug.log("ca=%s" % ca)
        b_all = ugtk.StockButton(gtk.STOCK_SELECT_ALL)
        b_all.connect('clicked', lambda w: dialog.select_all())
        b_all.set_tooltip_text("Select all files")
        # ugtk.pack_start_align(hbox, b_all, align=ugtk.ALIGN_LEFT)
        # ca.pack_start(self.user_filter_ui())
        ufui = self.user_filter_ui(dialog)
        hbox.pack_start(b_all, expand=False, fill=False, padding=1)
        hbox.pack_start(gtk.Label(""), expand=True, fill=True, padding=1)
        hbox.pack_end(ufui, expand=False, fill=False, padding=1)
        # ugtk.pack_start_align(hbox, ufui, align=ugtk.ALIGN_RIGHT)
        ca.pack_start(hbox, expand=False, fill=False, padding=0)
        ca.show_all()
        response = dialog.run()
        debug.log("response=%d" % response)
        if response == gtk.RESPONSE_OK:
            filenames = dialog.get_filenames()
            debug.log("%d filenames: %s" % (len(filenames), filenames))
            n = len(filenames)
            if n > 0:
                self.source_files = filenames
                t = filenames[0]
                if n > 1:
                    t = "%d files from %s" % (n, os.path.dirname(t))
                self.label_sources.set_text(t)
        dialog.destroy()


    def select_target_directory(self, w):
        debug.log("")
        fsdir = ugtk.select_fs_directory(
            title="Select target directory for JPEG files",
            parent=self)
        if not fsdir is None:
            self.target_directory = fsdir
            self.label_target.set_text(fsdir)


    def user_filter_ui(self, fs_dialog):
        debug.log("")
        h = gtk.HBox()
        h.pack_start(gtk.Label("Filter:"), expand=False, fill=False, padding=1)
        e = gtk.Entry()
        e.connect('activate', self.update_filter, fs_dialog)
        e.connect('focus-out-event', self.update_filter, fs_dialog)
        h.pack_start(e, expand=False, fill=False, padding=1)
        return h


    def update_filter(self, entry, fs_dialog):
        debug.log("entry=%s, fs_dialog=%s" % (entry, fs_dialog))
        s = entry.get_text()
        debug.log("text=%s" % s)
        new_pattern = s.strip()
        if new_pattern != s:
            debug.log("stripped '%s' -> '%s'" % (s, new_pattern))
            entry.set_text(new_pattern)
        if self.pattern != new_pattern:
            self.pattern = new_pattern
            self.add_user_filter(fs_dialog)


    def add_user_filter(self, fs_dialog):
        debug.log("")
        if not self.user_filter is None:
            fs_dialog.remove_filter(self.user_filter)
        if self.pattern != "":
            self.user_filter = ff = gtk.FileFilter()
            ff.set_name(self.pattern)
            ff.add_pattern(self.pattern)
            fs_dialog.add_filter(ff)
            fs_dialog.set_filter(ff)


    def raw2jpeg(self):
        debug.log("")
        self.common_suffix_len()
        self.next = 0
        self.n_failed = 0
        self.monitor = ugtk.Monitor(title=("""
Converting raw formatted  image files from %s
to JPEG formatted files in %s""" % (os.path.dirname(self.source_files[0]),
                                    self.target_directory)),
                               parent=self,
                               step_cb=self.raw2jpeg1)
        if not self.icon is None:
            self.monitor.set_icon(self.icon)
        done = self.monitor.run_monitor()
        self.monitor.destroy()
        return done


    def common_suffix_len(self):
        self.suffix_len = 0
        bn = os.path.basename(self.source_files[0])
        ss = string.split(bn, '.')
        if len(ss) >= 2:
            suffix = "." + ss[-1]
            suffix_len = len(suffix)
            common = True
            fi = 1
            while common and fi < len(self.source_files):
                bn = os.path.basename(self.source_files[fi])
                common = bn[-suffix_len:] == suffix
                fi += 1
            if common:
                self.suffix_len = suffix_len
        debug.log("suffix_len=%d" % suffix_len)


    def raw2jpeg1(self):
        debug.log("")
        status_text = None
        if self.next < len(self.source_files):
            status_text = self.do_raw2jpeg1()
        return status_text


    def do_raw2jpeg1(self):
        source_fn = self.source_files[self.next]
        bn = os.path.basename(source_fn)
        if self.suffix_len > 0:
            bn = bn[:-self.suffix_len]
        target_fn = "%s/%s.jpeg" % (self.target_directory, bn)
        self.monitor.external_status.set_text("""
Converting: %s
into:       %s"""[1:] % (source_fn, target_fn))
        ugtk.gtk_update()
        # We want to avoid writing a shell script with pipe on the file system
        # This is why we pipe the script to /bin/sh and pass parameters
        # via envionment variables
        conv_env = {'PATH': os.getenv('PATH'),
                    'CONV_SOURCE': source_fn,
                    'CONV_TARGET': target_fn}
        pipe_cmd = "%s -c ${CONV_SOURCE} | %s > ${CONV_TARGET}" % (
            dcraw, cjpeg)
        p = subprocess.Popen(["/bin/sh"], stdin=subprocess.PIPE, env=conv_env)
        p.stdin.write("%s\n" % pipe_cmd)
        p.stdin.close()
        rc = p.wait()
        debug.log("rc=%d target_fn=%s" % (rc,  target_fn))
        if rc == 0:
            key_orientation = 'Exif.Image.Orientation'
            top_left = pyexiv2.ExifTag(key_orientation, 1)
            exif_override = {key_orientation: top_left}
            convert.copy_metadata(source_fn, target_fn, exif_override)
        if rc != 0:
            self.monitor.external_status.set_text("Converting %s failed" %
                                                  source_fn)
            ugtk.gtk_update()
            usys.unlink(target_fn)
            time.sleep(1)
            self.n_failed += 1
        self.next += 1
        status_text = "Out of %d, converted %d, failed %d" % (
            len(self.source_files), self.next - self.n_failed, self.n_failed)
        return status_text


if __name__ == '__main__':

    import sys

    debug.debug_on = True

    def quit(w, *args):
        debug.log("w=%s, args=%s" % (w, str(args)))
        gtk.main_quit()
        debug.log("quit end")

    def activate(self, topwin):
        c = Converter(parent=topwin)
        response = c.run()
        debug.log("response=%d" % response)
        c.destroy()


    sys.stderr.write("%s begin\n" % sys.argv[0]);
    topwin = gtk.Window()
    topwin.set_size_request(200, 72)
    topwin.set_title("Raw Images Converter App")
    topwin.connect('destroy', quit, "des")
    topwin.connect('delete-event', quit, "del")
    vbox = gtk.VBox()
    vbox.pack_start(gtk.Label("Raw Images Converter\nApplication"))
    bact = gtk.Button("Activate")
    vbox.pack_start(bact)
    bact.connect('clicked', activate, topwin)
    topwin.add(vbox)
    topwin.show_all()
    debug.log("Calling gtk.main()")
    gtk.main()

    sys.stderr.write("%s end\n" % sys.argv[0]);
    sys.exit(0)
